﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO;


namespace zframe.loader {

    public delegate void LoadsCallBack(UnityEngine.Object[] assets);

    public class ResManager
    {
        private static ResManager _instance;

        public static ResManager Instance { 
            get {
                if (_instance == null) {
                    _instance = new ResManager(); 
                }
                return _instance;   
            }
        }

        //最大同时加载数
        private int _maxLoaderNum = 10;

        //加载中的
        private List<BaseResLoader> _loadingLoaders = new List<BaseResLoader> ();   
        private List<BaseResLoader> _waitinngLoaders = new List<BaseResLoader> ();   

        private string _resRoot = "";

        /// <summary>
        /// 远程根地址
        /// </summary>
        public string ResRoot { 
            get { 
                return _resRoot; 
            } set {
                _resRoot = value; 
            } 
        }

        public ResManager()
        {
            if (_instance !=null)
            {
                throw new Exception("ResManager是单例");
            }
            
        }
        private void Init() {
            _loadingLoaders = new List<BaseResLoader>();
            _waitinngLoaders = new List<BaseResLoader>();   

        }

        public void SetMaxLoader(int maxLoader)
        {
            _maxLoaderNum = maxLoader;   
        }

        public string GetUrl(string bundlerName)
        {
            bundlerName = bundlerName.ToLower();    
            return Path.Combine(ResRoot, bundlerName);
        }

        /// <summary>
        /// 一次加载多个ab包
        /// </summary>
        /// <param name="bundleNames"></param>
        /// <param name="loadsCall">回调函数,参数是加载完成的ab包，顺序不一定对应 bundleNames </param>
        public void LoadAssetBundles(string[] bundleNames,LoadsCallBack loadsCall=null)
        {
            int count = bundleNames.Length;
            int loadedCount = 0;
            UnityEngine.Object[] assets = new UnityEngine.Object[count];  
            for (int i = 0; i < count; i++)
            {
                LoadAssetBundle(bundleNames[i], (UnityEngine.Object asset, BaseResLoader loader ) =>
                {
                    assets.SetValue(asset, loadedCount);
                    loadedCount++;
                    if (loadedCount == count)
                    {
                        if (loadsCall !=null)
                        {
                            loadsCall.Invoke(assets);
                        }
                    }
                });
            }
        }

        /// <summary>
        /// 加载ab包
        /// </summary>
        /// <param name="bundlerName">ab包的名称</param>
        /// <param name="callBack">回调，如果传入始终都会执行回调;如果网络错误那么asset参数==null</param>
        public void LoadAssetBundle(string bundlerName,OnResLoaded callBack=null)
        {
            AssetBundleLoader loader = new AssetBundleLoader(GetUrl(bundlerName));
            if (_loadingLoaders.Count<_maxLoaderNum)
            {
                AddLoader(loader, callBack);
            }
            else
            {
                _waitinngLoaders.Add(loader);
                _waitinngLoaders.Sort(CompareLoader);
            }
        }

        private void AddLoader(BaseResLoader loader, OnResLoaded callBack = null)
        {
            Debug.Log("开始新的加载");
            _loadingLoaders.Add(loader);
            loader.Load();
            
            loader.OnResLoaded += (UnityEngine.Object asset,BaseResLoader resLoader) =>
            {
                if (callBack!=null)
                {
                    callBack.Invoke(asset, resLoader);
                }
                _loadingLoaders.Remove(loader);
                if (_waitinngLoaders.Count > 0)
                {
                    AddLoader(_waitinngLoaders[0]);
                    _waitinngLoaders.RemoveAt(0);
                }

            };
            
        }


        private int CompareLoader(BaseResLoader a, BaseResLoader b)
        {
            int ret = 0;
            if (a.Priority<b.Priority)
            {
                ret = 1;
            }
            else if(a.Priority > b.Priority)
            {
                ret = -1;
            }
            return ret; 
        }

    }
}
